package com.liu.project.controller.recommend;

import com.github.pagehelper.PageInfo;
import com.liu.project.kmeans.ClusterModel;
import com.liu.project.kmeans.UserBased2;
import com.liu.project.kmeans.kmeans;
import com.liu.project.pojo.Certificate;
import com.liu.project.service.CertificateService;
import com.liu.project.service.MajorService;
import com.liu.project.service.PerComService;
import com.liu.project.service.UserService;
import com.liu.project.utils.Message;
import com.liu.project.utils.RedisUtil;
import com.liu.project.utils.UserUtil;
import com.sun.jersey.api.core.PackagesResourceConfig;
import io.swagger.annotations.Api;
import io.swagger.models.auth.In;
import lombok.SneakyThrows;
import org.apache.commons.lang.ArrayUtils;
import org.apache.mahout.cf.taste.common.TasteException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import javax.websocket.server.PathParam;
import java.util.*;

/**
 * @program: project
 * @description: 推荐控制层
 * @author: 86187
 * @create: 2022-03-20 09:10
 **/
@Api(tags = "用户推荐",description = "将聚类算法结果与用户协同过滤结果混合推荐")
@Controller
@RequestMapping("/api/recom")
public class RecommController {

    @Autowired
    RedisUtil redisUtil;
    @Autowired
    CertificateService service;
    @Autowired
    private MajorService majorService;
    @Autowired
    UserBased2 userBased2;
    @Autowired
    UserService userService;
    @Autowired
    kmeans kmeans;
    @Autowired
    private PerComService perComService;
    @PostMapping("/ku/{x}/{y}")
    @ResponseBody
    public Message<List<Certificate>> recommend(@PathVariable("x") int x, @PathVariable("y") int y) throws TasteException {


        if (x<0 || y<0) return new Message<>(0,"抱歉，暂无数据");

        //kmeans聚类结果
        HashSet<Certificate> recomList = new HashSet<>();
        ClusterModel o = (ClusterModel)redisUtil.get("kmeans");
        double majorValue = majorService.getNameById(x);
        double m1 = kmeans.normalize_x(majorValue);
        List<Double> pfvalueByMbid = perComService.getPfvalueByMbid(y);
        double[] professValues = ArrayUtils.toPrimitive(pfvalueByMbid.toArray(new Double[pfvalueByMbid.size()]));


        for (int i=0;i<professValues.length;i++){
            if (redisUtil.get("xy:"+x+","+professValues[i])==null){//如果已经进行过计算，则直接从缓存取用，否则重新进行计算  按专业 和职业分类量化值作为可以存储
                double[] x_y={m1,kmeans.normalize_y(professValues[i])};//归一处理
                Map<double[], Double> dis=new HashMap<>();//存放计算的距离值  用户坐标为key和每个中心点距离

                for (int j = 0; j < o.originalCenters.length; j++) {//比较用户数值和每个中心点距离 ，将最近的存储到a中
                    dis.put(o.originalCenters[j],kmeans.dist(o.originalCenters[j],x_y,2));
                }
                List<Map.Entry<double[], Double>> entries = new ArrayList<>(dis.entrySet());
                Collections.sort(entries, new Comparator<Map.Entry<double[], Double>>() {
                    @Override
                    public int compare(Map.Entry<double[], Double> o1, Map.Entry<double[], Double> o2) {
                        return o2.getValue().compareTo(o1.getValue());
                    }
                    //是结果降序排序
                });

                double[] b_min = new double[o.data.dim];
                for (Map.Entry<double[], Double> doubleEntry : entries.subList(0, 1)) {
                    b_min=doubleEntry.getKey();//最近的中心点
                }
                for (int c = 0; c< o.originalCenters.length; c++) {
                    if (o.originalCenters[c]==b_min) {
                        int index = o.labels[o.perm[o.start[c]]];
                        int counts = o.centerCounts[index];
                        System.out.println(i+":"+counts+","+o.start[c]);
                        for (int y1 = o.start[c]; y1 < o.start[c]+counts; y1++) {
                            Certificate certificateById = service.findCertificateById(Integer.parseInt(o.iden0.get(o.perm[y1])));
                            recomList.add(certificateById);
                        }
                    }
                }
                redisUtil.set("xy:"+x+","+professValues[i],recomList);
            }else {
                recomList= (HashSet<Certificate>) redisUtil.get("xy:"+x+","+professValues[i]);
            }
        }


        //用户协同过滤
        int userId = UserUtil.getLoginUser().getId();
        List<Integer> userItemList = userBased2.UserBased2(Math.toIntExact(userId));
        //新用户无推荐数据 直接返回聚类结果
        if (userItemList != null)
            for (Integer integer : userItemList) {
                Certificate certificateById = service.findCertificateById(integer);
                recomList.add(certificateById);
            }


        return new Message<List<Certificate>>(200,"请求成功", new ArrayList<Certificate>(recomList));
    }

}


